home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
019
/
clock123.asm
< prev
next >
Wrap
Assembly Source File
|
1985-06-03
|
8KB
|
186 lines
interrupts segment at 0h
org 1ch*4 ; This is to use INT 1Ch
timer_int label dword ; which is the timer interupt
interrupts ends
screen segment at 0b000h ; A dummy segment to use
screen ends ; as the Extra Segment
code_seg segment
assume cs:code_seg
org 100h ; org = 100 to make this into
; a .COM file
first: jmp load_clock
old_time_int dd ? ; The address INT 1Ch normally uses
count500 dw 0 ; Used to update clock every 500 counts
cursor dw 0 ; Location of the cursor on the screen
video_port dw ? ; Video status port - ckeck for scanning
display dw 5 dup(133ah) ; Initial value for the clock
dw 3 dup(1320h) ; Add 3 ' 's for AM/PM.
clock proc near ; The timer INT will now come here
push ax ; Save the registers - good form
push cx
push di
push si
push es
pushf ; First call old time interrupt
call old_time_int
mov cx,count500 ; Prepare to test if we
inc cx ; should recalculate the time - done
cmp cx,500 ; every 500 timer counts
jb dont_recalculate
call calc ; Recalculate the time
mov cx,0 ; Reset Count500
dont_recalculate:
mov count500,cx ; Store incremented or cleared value
assume es:screen ; Set up screen as the Extra Segment
mov cx,screen
mov es,cx
mov dx,video_port ; This is the screen status port
mov di,cursor ; Set up cursor on screen as destination
lea si,display ; Set up the display in memory as source
mov cx,8 ; To move char only
cli
scan_low: ; Start waiting for a new horizontal scan
in al,dx ; i.e. the the vidio controller scan
test al,1 ; status is low.
jnz scan_low
mov ah,cs:[si] ; Move byte to be written into AH
scan_high: ; After port has gone low, it must go high
in al,dx ; before it is safe to write directly
test al,1 ; to the screen buffer in memory
jz scan_high
mov es:[di],ah ; Move to screen one byte at a time.
inc di ; Position to attribute byte
inc si ; on screen.
inc di ; Increment again to position
inc si ; past the attribute byte
loop scan_low ; Go back foe next byte
sti
pop es ; Here are required pops to exit
pop si
pop di
pop cx
pop ax
iret ; Aninterrupt needs an IRET
clock endp
calc proc near ; Here we recalculate the time and store it
push ax ; Puushes to save everytheing that
push bx ; gets destroyed
push cx
push dx
xor ax,ax ; Set up for clock read.
int 1ah ; Read the clock.
push dx ; Save low(minutes) portion.
mov ax,cx ; Move high(hours) portion to AX.
check: cmp ax,24 ; Make sure it's less than 24
jle valid_time
sub ax,24 ; If not, keep subtracting until it is.
jmp check
valid_time:
lea bx,display ; Set up BX as pointer to display in memory
mov byte ptr cs:[bx+14],'M' ; Move the 'M' into the display.
cmp ax,0 ; Is it between 12 & 1 AM?
jne after_1am ; No, check other times.
mov ax,012 ; Yes, make it '12',
jmp am ; and set to display 'AM'
after_1am:
cmp ax,12 ; Is it between 1 & 12 AM?
jl am ; Yes, set to display 'AM'
cmp ax,12 ; Is it between 12 & 1 PM?
je pm ; Yes, set to display 'PM'
sub ax,12 ; If not, take off another 12.
cmp ax,12 ; Is it after midnight?
je am ; Yes, set to display 'AM'
pm: mov byte ptr cs:[bx+12],'P' ; Otherwise move 'P' into the display.
jmp am_pm_done ; Continue.
am: mov byte ptr cs:[bx+12],'A' ; Move an 'A' into the display.
am_pm_done:
aam ; Convert AX to BCD - a nice command
add ax,3030h ; Add '0' to both bytes in AX to make ASCII
cmp ah,'0' ; Is the 1st diget '0'?
jne dont_edit ; Then don't blank the character.
mov ah,' ' ; Otherwise, put a space in AH.
dont_edit:
mov cs:[bx],ah ; Move first hours digit into display
mov cs:[bx+2],al ; Then the second digit
pop ax ; Get low portion of clock from stack.
mov cx,8 ; We want to multiply minutes by 60 and
shr ax,cl ; divide by 65536, so multiply by 60 and shift
mov dx,60 ; right 16 bits. 60 secs = 65536 ticks.
mul dl
shr ax,cl
aam ; Again convert AX to Binary Coded Decimal
add ax,3030h ; Add to make two ASCII characters
mov cs:[bx+6],ah ; and move them into the display in memory
mov cs:[bx+8],al
; Restore registers
pop dx
pop cx
pop bx
pop ax
ret
calc endp
load_clock proc near ; This procedure initializes everything
assume ds:interrupts ; The Data Segment will be the interrupt area
mov ax,interrupts
mov ds,ax
cli
mov ax,timer_int ; Get the old interrupt service routine
mov old_time_int,ax ; address and put it into our location
mov ax,timer_int[2] ; OLD_TIME_INT so we can still call it
mov old_time_int[2],ax
mov timer_int,offset clock ; Now load the address of our clock
mov timer_int[2],cs ; routine into TIMER_INT so the timer
; interrupt will call CLOCK
sti
mov ah,15 ; Ask for service 15 of INT 10H
int 10h ; This tells us how the display is set up
sub ah,20 ; Move to twenty places before edge
shl ah,1 ; Mult by two (char and attribute bytes)
mov byte ptr cursor,ah ; Move cursor to it's memory location
mov video_port,03bah ; Assume this is a monochrome display
test al,4 ; Is it?
jnz get_time ; Yes - jump out
add cursor,8000h ; No - set up for graphics display
mov video_port,03dah
get_time:
call calc ; This is to avoid showing 00:00 for first 500 counts
mov dx,offset load_clock ; Set up for everything but LOAD_CLOCK
int 27h ; to stay attached to DOS
load_clock endp
code_seg ends
end first ; END FIRST so 8088 will go to FIRST first